package org.fujene.diskblock.repli;

import static org.fujene.diskblock.repli.ReplicateContentDiskBlock.LookupType.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.fujene.diskblock.DiskBlock;
import org.fujene.memoryblock.MemoryBlock;
import org.fujene.memoryblock.repli.ReplicateContentBlock;
import org.fujene.structure.Constants;
import org.fujene.structure.Enumerates;
import org.fujene.structure.IndexQueue;
import org.fujene.structure.LookupPointer;
import org.fujene.toolbox.ByteConverter;
import org.fujene.toolbox.ContentHash;

public class ReplicateContentDiskBlock extends DiskBlock {
	public static enum LookupType {
		ALL, ID, NEXT, STR, SUPP,
	}

	public ReplicateContentDiskBlock(File fileDesc) throws Exception {
		super(fileDesc);
	}

	public ReplicateContentDiskBlock(ReplicateContentBlock memBlock, String dir) {
		super(memBlock, dir);
	}

	public ReplicateContentDiskBlock(int ID, File desc, int defaultBodySize,
			int defaultOptionSize) throws Exception {
		super(ID, desc, Constants.MEMORY_TYPE_CONTENTS, defaultBodySize,
				defaultOptionSize);
	}

	// P2Pバージョンの本文情報
	public class ExtentContents {
		private long contentID;
		private LookupPointer nextContent;
		private String str;
		private LookupPointer[] pointers;

		// 読み出し用
		public ExtentContents(int from, LookupType type) {
			if (from >= bodySize)
				return;

			FileInputStream stream = null;
			byte[] val = null;
			try {
				pointers = new LookupPointer[getOption(1)];

				stream = new FileInputStream(fileDesc);
				switch (version) {
				case Constants.FINALVER: // 0.30
					stream.skip((4 * HEADERLEN) + (4 * optionSize) + from);

					if (type == ALL || type == NEXT) {
						val = new byte[PTR];
						stream.read(val);
						this.nextContent = ByteConverter.getPtr(val);
					} else
						stream.skip(PTR);

					if (type == ALL || type == ID) {
						val = new byte[8];
						stream.read(val);
						this.contentID = ByteConverter.byteToLong(val);
					} else
						stream.skip(8);
					
					if (type == ALL || type == SUPP) {
						val = new byte[PTR];
						for (int i = 0; i < pointers.length; i++) {
							stream.read(val);
							this.pointers[i] = ByteConverter.getPtr(val);
						}
					} else
						stream.skip(PTR * pointers.length);
					
					int length = 0;
					if (type == ALL || type == STR) {
						val = new byte[STRLEN];
						stream.read(val);
						length = ByteConverter.byteToInt(val);
					} else
						stream.skip(STRLEN);

					if (type == ALL || type == STR) {
						val = new byte[length];
						stream.read(val);
						str = new String(val, "UTF-8");
					}
					break;

				default:
					break;
				}
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
			} catch (Exception e) {
			} finally {
				if (stream != null)
					try {
						stream.close();
					} catch (IOException e) {
					}
			}
		}

		public long getContentID() {
			return contentID;
		}

		public LookupPointer getNextContent() {
			return nextContent;
		}

		public String getStr() {
			return str;
		}
	}

	public String getContent(int ptr) {
		return new ExtentContents(ptr, ALL).getStr();
	}

	public IndexQueue getContentWithID(int ptr) {
		ExtentContents ptred = new ExtentContents(ptr, ALL);
		return new IndexQueue(Enumerates.INDEX, ptred.getStr(),
				ContentHash.getContentHash(ptred.getContentID()),
				ptred.getContentID(), 0);
	}

	public long getContentID(int ptr) {
		return new ExtentContents(ptr, ID).getContentID();
	}

	public LookupPointer getNextContentPointer(int ptr) {
		ExtentContents ptred = new ExtentContents(ptr, NEXT);
		LookupPointer retPtr = ptred.getNextContent();
		if (retPtr.equals(Constants.emptyPointer))
			return null;
		else
			return retPtr;
	}
	
	public LookupPointer[] getSupplementPointer(int ptr){
		ExtentContents ptred = new ExtentContents(ptr, SUPP);
		
		return ptred.pointers;
	}

	public int getCount() throws Exception {
		return this.getOption(0);
	}
	
	@Override
	public void readToMemory(MemoryBlock memBlock) {
		if (memBlock instanceof ReplicateContentBlock) {
			try {
				memBlock.setOption(0, this.getOption(0));
				memBlock.setBody(this.getBody(0, this.bodySize), 0);
				memBlock.setBodyVacancy(this.bodyVacancy);
			} catch (Exception e) {
			}
		}
	}

	@Override
	public byte[] getData() {
		throw new NoSuchMethodError("Unimplemented method");
	}
}
